﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebLayer;
using System.Collections;

namespace SpeakupBackend.Classes
{

    public class ClassRequestStartedEventArgs : EventArgs
    {
        public ClassRequestStartedEventArgs(Class speakupClass)
        {
            m_class = speakupClass;
        }

        Class m_class;
        public Class Class
        {
            get
            {
                return m_class;
            }
        }
    }

    public class ClassRequestResultEventArgs: EventArgs
    {
        public ClassRequestResultEventArgs(Class speakupClass, string message)
        {
            m_class = speakupClass;
            m_message = message;
        }

        Class m_class;
        public Class Class
        {
            get
            {
                return m_class;
            }
        }

        string m_message;
        public string Message
        {
            get
            {
                return m_message;
            }
        }
    }

    public class ClassVerificationStartedEventArgs : EventArgs
    {
        public ClassVerificationStartedEventArgs(Class speakupClass)
        {
            m_class = speakupClass;
        }

        Class m_class;
        public Class Class
        {
            get
            {
                return m_class;
            }
        }
    }


    public class ClassVerificationResultEventArgs: EventArgs
    {
        public ClassVerificationResultEventArgs(Class speakupClass, bool verified)
        {
            m_class = speakupClass;
            m_verified = verified;
            m_message = null;
        }

        Class m_class;
        public Class Class
        {
            get
            {
                return m_class;
            }
        }

        bool m_verified;
        public bool Verified
        {
            get
            {
                return m_verified;
            }
        }

        string m_message;
        string Message
        {
            get
            {
                return m_message;
            }
        }

    }

    public partial class ClassActionSupervisor: ICollection<Class>
    {
        List<Class> Classes = new List<Class>();
                
        public int Count 
        { 
            get
            {
                return Classes.Count;
            }
        }

        public bool IsReadOnly 
        {
            get
            {
                return ((ICollection<Class>)Classes).IsReadOnly;
            }
        }

        public void Add(Class item)
        {
            Classes.Add(item);
        }

        public void Clear()
        {
            Classes.Clear();
        }

        public bool Contains(Class item)
        {
            return Classes.Contains(item);
        }

        public void CopyTo(Class[] array, int arrayIndex)
        {
            Classes.CopyTo(array, arrayIndex);
        }

        public bool Remove(Class item)
        {
            return Classes.Remove(item);
        }

        public IEnumerator<Class> GetEnumerator()
        {
            return Classes.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)Classes).GetEnumerator();
        }
    }

    public partial class ClassActionSupervisor
    {        
        Dictionary<Class, String> RequestResults;
        Dictionary<Class, bool> VerificaionResults;

        struct ClassState
        {
            public ClassState(Class cl)
            {
                m_current = cl.CurrentStatus;
                m_desired = cl.DesiredStatus;
                m_action = cl.Action;
            }

            ClassAction m_action;
            public ClassAction Action
            {
                get
                {
                    return m_action;
                }
            }

            ClassStatus m_current;
            public ClassStatus CurrentStatus
            {
                get
                {
                    return m_current;
                }
            }

            ClassStatus m_desired;
            public ClassStatus DesiredStatus
            {
                get
                {
                    return m_desired;
                }
            }
        }

        public ClassActionSupervisor()
        {

        }
        
        public ClassActionSupervisor(IEnumerable<Class> classes)
        {
            if (classes != null)
            {
                Classes.AddRange(classes);
            }
        }
        
        public void ApplyActions(LoginToken token)
        {
            RequestResults = new Dictionary<Class, string>();
            VerificaionResults = new Dictionary<Class, bool>();

            Dictionary<Class, ClassState> classStates = new Dictionary<Class, ClassState>();

            //go and do request on all classes
            foreach (Class speakupClass in Classes)
            {
                string serverMessage;

                classStates.Add(speakupClass, new ClassState(speakupClass));

                if (speakupClass.Action == ClassAction.None)
                {
                    serverMessage = "Nothing to be done.";
                }
                else
                {
                    OnRequestStarted(speakupClass);
                    speakupClass.ApplyAction(out serverMessage, token);
                }

                RequestResults.Add(speakupClass, serverMessage);
                OnRequestResult(speakupClass, serverMessage);
            }

            //verify
            foreach (Class speakupClass in Classes)
            {
                OnVerificationStarted(speakupClass);
            }

            ClassList newClasses = ClassListFetcher.FetchFutureClasses(token);

            foreach (Class speakupClass in Classes)
            {
                bool verified = false;

                Class verifiedClass = newClasses.Find(cl => cl.Id == speakupClass.Id);
                if (verifiedClass != null)
                {
                    if (verifiedClass.CurrentStatus == classStates[speakupClass].DesiredStatus)
                    {
                        verified = true;
                    }
                }

                VerificaionResults.Add(speakupClass, verified);
                OnVerificationResult(speakupClass, verified);

                //restore class state that class had before applying action
                if (!verified)
                {
                    speakupClass.RevertAction(classStates[speakupClass].CurrentStatus, 
                                              classStates[speakupClass].Action);
                }                
            }
        }

        public event EventHandler<ClassRequestStartedEventArgs> RequestStarted;

        protected void OnRequestStarted(Class cl)
        {
            EventHandler<ClassRequestStartedEventArgs> handler = RequestStarted;
            if (handler != null)
            {
                ClassRequestStartedEventArgs args = new ClassRequestStartedEventArgs(cl);
                handler(this, args);
            }
        }

        public event EventHandler<ClassRequestResultEventArgs> RequestResult;

        protected void OnRequestResult(Class cl, string msg)
        {
            EventHandler<ClassRequestResultEventArgs> handler = RequestResult;
            if (handler != null)
            {
                ClassRequestResultEventArgs args = new ClassRequestResultEventArgs(cl, msg);
                handler(this, args);
            }
        }

        public event EventHandler<ClassVerificationStartedEventArgs> VerificationStarted;

        protected void OnVerificationStarted(Class cl)
        {
            EventHandler<ClassVerificationStartedEventArgs> handler = VerificationStarted;

            if (handler != null)
            {
                ClassVerificationStartedEventArgs args = new ClassVerificationStartedEventArgs(cl);
                handler(this, args);
            }

        }


        public event EventHandler<ClassVerificationResultEventArgs> VerificationResult;
        protected void OnVerificationResult(Class cl, bool result)
        {
            EventHandler<ClassVerificationResultEventArgs> handler = VerificationResult;

            if (handler != null)
            {
                ClassVerificationResultEventArgs args = new ClassVerificationResultEventArgs(cl, result);
                handler(this, args);
            }

        }
    }
}
